package com.starsoft.frame.fileimport;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.starsoft.frame.fileimport.pojo.Column;
import com.starsoft.frame.fileimport.pojo.DataTable;
import com.starsoft.frame.fileimport.pojo.NullType;
import com.starsoft.frame.fileimport.pojo.Table;
import com.starsoft.frame.fileimport.pojo.ValueType;
import com.starsoft.frame.fileimport.pojo.Table.TitleType;
import com.starsoft.frame.util.StringUtil;

public class CsvReader extends FileReaderImpl {

	private String charset = "GBK";
	private boolean isTransform;

	public CsvReader() {

	}
	
	public CsvReader(boolean isTransform){
		this.isTransform=isTransform;
	}
	
	@Override
	public DataTable read(String content, Table table) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		List<String> listStrings = getLineStrings(content);
		readTitle(listStrings, table);
		dataTable.setData(readData(listStrings, table));
		return dataTable;
	}

	@Override
	public DataTable read(InputStream source, Table table) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		List<String> listStrings = getLineStrings(source);
		readTitle(listStrings, table);
		dataTable.setData(readData(listStrings, table));
		return dataTable;
	}

	private List<Map<String, Object>> readData(List<String> listStrings, Table table) {
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();

		List<Column> columnList = table.getColumnList();
		for (int index = table.getStartRow(); index < table.getEndRow(); index++) {
			Map<String, Object> rowMap = new HashMap<String, Object>();
			String[] row = listStrings.get(index).split(",");
			for (Column column : columnList) {
				if (row.length <= column.getColIndex()) {
					if (column.getNullType() != NullType.nullable) {
						throw new RuntimeException((index + 1) + " row:" + column.getName() + " can not be null");
					}
					continue;
				}
				String value = removeQoute(row[column.getColIndex()]);
				Object ob = str2Obj(value, column.getValueType(), column.getFormat());
				if (ob == null && column.getNullType() == NullType.nullable) {
					ob = column.getDefaultValue();
				} else if (ob == null && column.getNullType() != NullType.nullable) {
					throw new RuntimeException((index + 1) + " row:" + column.getName() + " can not be null");
				}
				rowMap.put(column.getMapKey(), ob);
			}
			data.add(rowMap);
		}
		return data;
	}

	private void readTitle(List<String> listStrings, Table table) {
		if (table.getEndRow() < 0) {
			table.setEndRow(listStrings.size());
		}
		if (table.getEndCol() < 0) {
			String[] data = listStrings.get(0).split(",");
			table.setEndCol(data.length);
		}

		int colNum = listStrings.get(0).split(",").length;
		String[] names = new String[colNum];
		String[] codes = new String[colNum];
		ValueType[] types = new ValueType[colNum];
		NullType[] nullTypes = new NullType[colNum];
		Object[] defaults = new Object[colNum];
		Integer[] colIndex = new Integer[colNum];

		if (table.getNameRow() >= 0) {
			String[] row = listStrings.get(table.getNameRow()).split(",");
			for (int i = 0; i < colNum; i++) {
				names[i] =removeQoute(row[i]);
				colIndex[i] = i + table.getStartCol();
			}
		}
		if (table.getCodeRow() >= 0) {
			String[] row = listStrings.get(table.getCodeRow()).split(",");
			for (int i = 0; i < colNum; i++) {
				String typestr = removeQoute(row[i]);
				String[] values = StringUtil.split2Array(typestr, "/");
				colIndex[i] = i + table.getStartCol();
				if (values.length > 0) {
					codes[i] = values[0];
				}
				if (values.length > 1) {
					types[i] = ValueType.toEnum(values[1]);
				}
				if (values.length > 2) {
					nullTypes[i] = NullType.toEnum(values[2]);
				}
				if (values.length > 3) {
					defaults[i] = str2Obj(values[3], types[i]);
				}
			}
		}
		List<Column> columnList = table.getColumnList();
		if (columnList == null) {
			columnList = new ArrayList<Column>();
			for (int i = 0; i < colNum; i++) {
				Column column = new Column(colIndex[i], codes[i], names[i], types[i], nullTypes[i],
						defaults[i]);
				columnList.add(column);
			}
			table.setColumnList(columnList);
		} else {
			for (int i = 0; i < colNum; i++) {
				Column column;
				if (TitleType.OnlyName.equals(table.getTitleType())) {
					column = table.getColumnByName(names[i]);
				} else {
					column = table.getColumnByCode(codes[i]);
				}
				if (column != null) {
					column.updateIf(colIndex[i], codes[i], names[i], types[i], nullTypes[i],
							defaults[i]);
				}
			}
		}
	}

	private String removeQoute(String value) {
		String result = value;
		if (!StringUtil.isEmpty(value) && value.startsWith("\"") && value.endsWith("\"")) {
			result = value.substring(1, value.length() - 1);
		}
		return result;
	}
	
	private List<String> getLineStrings(InputStream source) {
		List<String> result = new ArrayList<String>();
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(source, charset));
			String line;
			while ((line = reader.readLine()) != null) {
				result.add(line);
			}
		} catch (Exception e) {
			throw new RuntimeException("get sheet error:" + e.getMessage());
		}
		return result;
	}

	private List<String> getLineStrings(String source) {
		String enter = "\n";
		int index = source.indexOf("\r\n");
		if(index>0){
			enter = "\r\n";
		}
		String[] splitSource = source.split(enter);
		if (!isTransform) {
			return Arrays.asList(splitSource);
		} else {
			List<String> resultList = new ArrayList<String>();
			String[][] split2 = new String[splitSource.length][];
			for (int i = 0; i < splitSource.length; i++) {
				split2[i] = splitSource[i].split(",");
			}
			for (int i = 0; i < split2[0].length; i++) {
				StringBuffer sb = new StringBuffer(split2[0][i]);
				for (int j = 1; j < split2.length; j++) {
					sb.append(",").append(split2[j][i]);
				}
				resultList.add(sb.toString());
			}
			return resultList;
		}
	}
	
	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

}
